<template>
	<view class="v-tabs">
		<scroll-view scroll-x class="tabs-scroll" :scroll-left="scrollLeft" :show-scrollbar="false" :scroll-with-animation="true">
			<view class="tabs-container">
				<view
					v-for="(item, index) in tabs"
					:key="item.key || index"
					class="tab-item"
					:class="[{ active: index === activeIndex }, hoverClass]"
					:style="{
						minWidth: `${minTabWidth}rpx`,
						padding: `0 ${itemPadding}rpx`
					}"
					@click="handleTabClick(index)"
					:id="`tab_${index}`"
				>
					<text class="tab-text">{{ item.title }}</text>
				</view>
				<view v-show="isLine" class="tab-line" :style="lineStyle"></view>
			</view>
		</scroll-view>
	</view>
</template>

<script lang="ts" setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue';

interface TabList {
	title: string;
	key: string;
}

/**
 * v-tabs 	标签页 无内容
 * value	双向绑定值	默认值:0
 * tabs		标签标题
 * activeColor	高亮颜色		默认值:#287afa
 * inactiveColor	标题颜色		默认值:#666
 * isLine		是否显示下划线	默认值:true
 * lineWidth		下划线宽度	默认值:最大标题宽度
 * lineHeight		下划线厚度	默认值:8
 * lineOffset		下划线距离标题距离	默认值:4
 * minTabWidth		最小标题宽度		默认值:120
 * itemPadding		标题内边距		默认值:32
 * hoverClass		悬浮名称			默认值:tabs-hover
 * 相关事件:change
 */
const props = defineProps({
	value: {
		type: Number,
		default: 0
	},
	tabs: {
		type: Array as () => TabList[],
		required: true
	},
	activeColor: {
		type: String,
		default: '#287afa'
	},
	inactiveColor: {
		type: String,
		default: '#666'
	},
	isLine: {
		type: Boolean,
		default: true
	},
	lineHeight: {
		type: String,
		default: '8'
	},
	lineWidth: {
		type: Number,
		default: 20
	},
	lineOffset: {
		type: Number,
		default: 0
	},
	minTabWidth: {
		type: Number,
		default: 120
	},
	itemPadding: {
		type: Number,
		default: 32
	},
	hoverClass: {
		type: String,
		default: 'tabs-hover'
	}
});

const emit = defineEmits(['update:value', 'change']);

const activeIndex = ref(props.value);
const tabRects = ref<{ left: number; width: number }[]>([]);
const scrollLeft = ref(0);
const isLandscape = ref(false);

const lineStyle = computed(() => {
	if (!tabRects.value[activeIndex.value]) return {};
	const current = tabRects.value[activeIndex.value];
	return {
		width: `${props.lineWidth === 0 ? current.width : props.lineWidth}px`,
		transform: `translateX(${current.left}px)`,
		backgroundColor: props.activeColor,
		height: uni.upx2px(parseFloat(props.lineHeight)) + 'px',
		bottom: `2rpx`
	};
});

let updateTimer = null;
const updateTabRects = () => {
	clearTimeout(updateTimer);
	updateTimer = setTimeout(() => {
		nextTick(() => {
			uni.createSelectorQuery()
				.selectAll('.tab-item')
				.boundingClientRect((rects: any) => {
					tabRects.value = rects.map((rect: any) => ({
						left: rect.left - (rects[0]?.left || 0),
						width: rect.width
					}));
				})
				.exec();
		});
	}, 100);
};

const handleTabClick = (index: number) => {
	if (activeIndex.value === index) return;
	activeIndex.value = index;
	scrollToTab(index);
	emit('change', index);
};

const scrollToTab = (index: number) => {
	const current = tabRects.value[index];
	if (!current) return;

	const systemInfo = uni.getSystemInfoSync();
	const tabWidth = current.width;
	const tabLeft = current.left;

	const viewCenter = systemInfo.windowWidth / 2;
	const tabCenter = tabLeft + tabWidth / 2;
	const targetScroll = Math.max(0, tabCenter - viewCenter);

	requestAnimationFrame(() => {
		scrollLeft.value = targetScroll;
	});
};

const checkOrientation = () => {
	const { windowWidth, windowHeight } = uni.getSystemInfoSync();
	isLandscape.value = windowWidth > windowHeight;
	updateTabRects();
	scrollToTab(activeIndex.value);
};

watch(activeIndex, (val) => {
	emit('update:value', val);
});

onMounted(() => {
	checkOrientation();
	uni.onWindowResize(checkOrientation);
});

watch(() => props.tabs, updateTabRects);
</script>

<style lang="scss" scoped>
.v-tabs {
	width: 100%;
	background-color: #fff;
	position: relative;
	padding: 0 env(safe-area-inset-left);
}

.tabs-scroll {
	width: 100%;
	white-space: nowrap;
	padding: 0 env(safe-area-inset-right);
}

.tabs-container {
	position: relative;
	display: inline-flex;
	height: 80rpx;
	align-items: center;
	padding: 0 20rpx;
	will-change: transform;
}

.tab-item {
	position: relative;
	height: 100%;
	display: inline-flex;
	align-items: center;
	transition: color 0.3s;
	flex-shrink: 0;

	&.active {
		.tab-text {
			color: v-bind('props.activeColor');
			font-weight: 500;
		}
	}

	.tab-text {
		margin: auto;
		font-size: clamp(24rpx, 4vw, 32rpx);
		color: v-bind('props.inactiveColor');
		transition: color 0.3s;
	}
}

.tab-line {
	position: absolute;
	bottom: 0;
	border-radius: v-bind('props.lineHeight');
	transition: all 0.3s cubic-bezier(0.35, 0, 0.25, 1);
	transform-origin: 0 50%;
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
}

.tabs-hover {
	opacity: 0.6;
	transition: opacity 0.2s;
}
</style>
